﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using FreeSilverlightChart;
using System.Collections.Generic;

namespace AdvanceUsage
{
  public partial class Page : UserControl
  {
    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);
    }

    public void Page_Loaded(object o, EventArgs e)
    {
      _hdoc = HtmlPage.Document;

      _loadInitialChartValuesAndLabels();

      // setup the event handlers
      HtmlElement element = _hdoc.GetElementById("loadChartButton");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.LoadChart));

      element = _hdoc.GetElementById("addGroup");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.AddGroup));

      element = _hdoc.GetElementById("addSeries");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.AddSeries));

      element = _hdoc.GetElementById("addYValue");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.AddYValue));

      element = _hdoc.GetElementById("addXValue");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.AddXValue));

      element = _hdoc.GetElementById("addSeriesColors");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.AddSeriesColors));

      element = _hdoc.GetElementById("removeGroup");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.RemoveGroup));

      element = _hdoc.GetElementById("removeSeries");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.RemoveSeries));

      element = _hdoc.GetElementById("removeYValue");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.RemoveYValue));

      element = _hdoc.GetElementById("removeXValue");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this.RemoveXValue));

      element = _hdoc.GetElementById("graphType");
      element.AttachEvent("onchange",
          new EventHandler<HtmlEventArgs>(this._graphTypeChange));

      element = _hdoc.GetElementById("skin");
      element.AttachEvent("onchange",
          new EventHandler<HtmlEventArgs>(this._lookAndFeelChange));

      element = _hdoc.GetElementById("changeSkin");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this._setupImageClickHandler));

      element = _hdoc.GetElementById("changePerspective");
      element.AttachEvent("onclick",
          new EventHandler<HtmlEventArgs>(this._setupImageClickHandler));

      _setupImageClickHandler(null, null);

      LoadChart(null, null);
    }

    private void _setupImageClickHandler(object sender, HtmlEventArgs args)
    {
      for (int i = 0; i < _imageIDs.GetUpperBound(0) + 1; ++i)
      {
        HtmlElement element = _hdoc.GetElementById(_imageIDs[i, 0]);
        if (element != null)
        {
          element.AttachEvent("onclick", new EventHandler<HtmlEventArgs>(this._imageClicked));
        }
      }
    }

    private void _loadInitialChartValuesAndLabels()
    {
      _fillLabels(_seriesLabels, "seriesLabels");
      _fillLabels(_groupLabels, "groupLabels");
      _fillLabels(_seriesColors, "seriesColors");
      _fillValues(_chartYValues, "chartYValues", _seriesLabels.Length);
      _fillValues(_chartXValues, "chartXValues", _seriesLabels.Length);
      _hdoc.GetElementById("maxValueY").SetAttribute("value", "200000");
      _seriesCount = 3;
    }

    private void _loadPieChartValuesAndLabels()
    {
      _fillLabels(_pieSeriesLabels, "seriesLabels");
      _fillLabels(_pieGroupLabels, "groupLabels");
      _fillValues(_pieChartYValues, "chartYValues", _pieSeriesLabels.Length);
      _seriesCount = 6;
    }

    private void _loadGaugeChartValuesAndLabels()
    {
      _fillLabels(_gaugeSeriesLabels, "seriesLabels");
      _fillLabels(_gaugeGroupLabels, "groupLabels");
      _fillValues(_gaugeChartYValues, "chartYValues", _gaugeSeriesLabels.Length);
      _hdoc.GetElementById("maxValueY").SetAttribute("value", "200");
    }

    private void _fillLabels(string[] labels, string id)
    {
      HtmlElement table = _hdoc.GetElementById(id);

      while (table.Children.Count > 0)
      {
        table.RemoveChild(table.Children[0]);
      }

      HtmlElement row, cell, input;
      HtmlElement tBody = _hdoc.CreateElement("TBODY");

      table.AppendChild(tBody);

      for (int i = 0; i < labels.Length; ++i)
      {
        row = _hdoc.CreateElement("TR");
        tBody.AppendChild(row);
        cell = _hdoc.CreateElement("TD");
        row.AppendChild(cell);

        input = _hdoc.CreateElement("INPUT");
        input.SetStyleAttribute("width", "80px");
        cell.AppendChild(input);

        input.SetAttribute("value", labels[i]);
      }
    }

    private void _fillValues(double[,] values, string id, int seriesCount)
    {
      HtmlElement table = _hdoc.GetElementById(id);

      while (table.Children.Count > 0)
      {
        table.RemoveChild(table.Children[0]);
      }

      HtmlElement row, cell, input;
      HtmlElement tBody = _hdoc.CreateElement("TBODY");

      table.AppendChild(tBody);

      int rows = values.GetUpperBound(0) + 1;
      for (int i = 0; i < rows; i++)
      {
        row = _hdoc.CreateElement("TR");
        tBody.AppendChild(row);

        for (int j = 0; j < seriesCount; j++)
        {
          cell = _hdoc.CreateElement("TD");
          row.AppendChild(cell);

          input = _hdoc.CreateElement("INPUT");
          input.SetStyleAttribute("width", "50px");
          cell.AppendChild(input);

          input.SetAttribute("value", values[i, j].ToString());
        }
      }
    }

    private void AddGroup(object sender, HtmlEventArgs args)
    {
      _addLabelIntoTable("groupLabels");
    }

    private void AddSeries(object sender, HtmlEventArgs args)
    {
      _addLabelIntoTable("seriesLabels");
    }

    private void AddYValue(object sender, HtmlEventArgs args)
    {
      _addValuesIntoTable("chartYValues");
    }

    private void AddXValue(object sender, HtmlEventArgs args)
    {
      _addValuesIntoTable("chartXValues");
    }

    private void AddSeriesColors(object sender, HtmlEventArgs args)
    {
    }

    private void _addLabelIntoTable(string id)
    {
      HtmlElement table = _hdoc.GetElementById(id);
      HtmlElementCollection children = table.Children;

      int childCount = children.Count;

      HtmlElement tBody = children[childCount - 1];
      HtmlElement row, cell, input;

      row = _hdoc.CreateElement("TR");
      tBody.AppendChild(row);
      var random = new Random();
      cell = _hdoc.CreateElement("TD");
      row.AppendChild(cell);

      input = _hdoc.CreateElement("INPUT");
      input.SetStyleAttribute("width", "80px");
      cell.AppendChild(input);

      string value;
      if ("seriesLabels".Equals(id))
      {
        _seriesCount = tBody.Children.Count;
        value = "S" + _seriesCount;
      }
      else
        value = "G" + tBody.Children.Count;

      input.SetAttribute("value", value.ToString());
    }

    private void _addValuesIntoTable(string id)
    {
      HtmlElement table = _hdoc.GetElementById(id);

      HtmlElementCollection children = table.Children;
      int childCount = children.Count;

      HtmlElement tBody = children[childCount - 1];

      HtmlElement row, cell, input;

      row = _hdoc.CreateElement("TR");
      tBody.AppendChild(row);
      var random = new Random();
      for (int j = 0; j < _seriesCount; j++)
      {
        cell = _hdoc.CreateElement("TD");
        row.AppendChild(cell);

        input = _hdoc.CreateElement("INPUT");
        input.SetStyleAttribute("width", "50px");
        cell.AppendChild(input);

        double value = "chartYValues".Equals(id) ?
                        random.Next(100000, 200000) :
                        ((double)random.Next(6000, 10000)) / 1000.0;

        input.SetAttribute("value", value.ToString());
      }
    }

    private void RemoveGroup(object sender, HtmlEventArgs args)
    {
      _removeRowFromTable("groupLabels");
    }

    private void RemoveSeries(object sender, HtmlEventArgs args)
    {
      _removeRowFromTable("seriesLabels");
    }

    private void RemoveYValue(object sender, HtmlEventArgs args)
    {
      _removeRowFromTable("chartYValues");
    }

    private void RemoveXValue(object sender, HtmlEventArgs args)
    {
      _removeRowFromTable("chartXValues");
    }

    private void _imageClicked(object sender, HtmlEventArgs args)
    {
      string id = (sender as HtmlElement).Id;
      HtmlElement element = _hdoc.GetElementById("graphType");

      for (int i = 0; i < _imageIDs.GetUpperBound(0) + 1; ++i)
      {
        if (id.Equals(_imageIDs[i, 0]))
        {
          element.SetAttribute("value", _imageIDs[i, 1]);
          _lookAndFeelChange(_hdoc.GetElementById("skin"), null);
          _graphTypeChange(element, null);
          LoadChart(null, null);
          break;
        }
      }
    }

    private void _graphTypeChange(object sender, HtmlEventArgs args)
    {
      string graphType = (sender as HtmlElement).GetAttribute("value");

      if (graphType == Chart.ChartType.HBAR.ToString() ||
         graphType == Chart.ChartType.HBAR_STACKED.ToString() ||
         graphType == Chart.ChartType.RADAR.ToString() ||
         graphType == Chart.ChartType.RADAR_AREA.ToString())
      {
        _hdoc.GetElementById("format").SetAttribute("value", "$#0");

        if (_isGuageType || _isPieType)
        {
          _loadInitialChartValuesAndLabels();
          _isGuageType = _isPieType = false;
        }
      }
      else if (graphType == Chart.ChartType.CIRCULAR_GAUGE.ToString() ||
         graphType == Chart.ChartType.SEMI_CIRCULAR_GAUGE.ToString())
      {
        _hdoc.GetElementById("format").SetAttribute("value", "#0");
        _loadGaugeChartValuesAndLabels();
        _isGuageType = true;
      }
      else if (graphType == Chart.ChartType.PIE.ToString() ||
         graphType == Chart.ChartType.FUNNEL.ToString())
      {
        _loadPieChartValuesAndLabels();
        _isPieType = true;
      }
      else
      {
        _hdoc.GetElementById("format").SetAttribute("value", "$#,##0.00;($#,##0.00);0");

        if (_isGuageType || _isPieType)
        {
          _loadInitialChartValuesAndLabels();
          _isGuageType = _isPieType = false;
        }
      }

      if (graphType == Chart.ChartType.HBAR_STACKED.ToString() ||
         graphType == Chart.ChartType.VBAR_STACKED.ToString() ||
         graphType == Chart.ChartType.AREA_STACKED.ToString())
      {
        _hdoc.GetElementById("maxValueY").SetAttribute("value", "600000");
      }
      else
      {
        if (!_isGuageType)
          _hdoc.GetElementById("maxValueY").SetAttribute("value", "200000");
      }
    }

    private void _lookAndFeelChange(object sender, HtmlEventArgs args)
    {
      if (_transparentLF == null)
      {
        _transparentLF = new TransparentLookAndFeel();
        Chart.RegisterLookAndFeel(_transparentLF);
      }
      string lf = (sender as HtmlElement).GetAttribute("value");
      Chart.CurrentLookAndFeelId = lf;
    }

    private void _removeRowFromTable(string id)
    {
      HtmlElement table = _hdoc.GetElementById(id);

      HtmlElementCollection children = table.Children;
      int childCount = children.Count;

      HtmlElement tBody = children[childCount - 1];
      children = tBody.Children;
      tBody.RemoveChild(children[children.Count - 1]);

    }

    public void LoadChart(object sender, HtmlEventArgs args)
    {
      // retrieve the desired parameters from the test page
      string typeStr = _getSelectElementValue("graphType");
      Chart.ChartType chartType = (Chart.ChartType)
                                    Enum.Parse(typeof(Chart.ChartType), typeStr, true);

      bool isPerspective = "true".Equals(
                              _hdoc.GetElementById("Perspective").
                              GetAttribute("checked").ToLower());

      string legendStr = _getSelectElementValue("legend");
      Chart.LegendLocation location = (Chart.LegendLocation)
                                Enum.Parse(typeof(Chart.LegendLocation), legendStr, true);

      int yMajorCount = int.Parse(_hdoc.GetElementById("yMajorCount").GetAttribute("value"));
      double animDur = double.Parse(_hdoc.GetElementById("animDur").GetAttribute("value"));

      String format = _hdoc.GetElementById("format").GetAttribute("value");

      // Load the chart model from the test page
      ChartModel model = _loadChartModel();

      // create the chart and set the prefered properties
      Chart chart = Chart.CreateChart(chartType, model);
      chart.IsPerspective = isPerspective;
      chart.LegendPosition = location;
      chart.AnimationDuration = animDur;
      chart.YMajorGridCount = yMajorCount;
      chart.Format = format;

      chart.SetBounds(new Rect(0, 0, parentCanvas.Width, parentCanvas.Height));
      // add the custom component
      parentCanvas.Children.Add(chart);

      // setup the event handler
      chart.ChartClicked += new ChartEventHandler(ChartClicked);
      // now draw it
      chart.Draw();
    }

    private void ChartClicked(object sender, ChartEventArgs e)
    {
      alertText.Text = e.ToString();

      RectangleGeometry rg = alertRect.Data as RectangleGeometry;
      Rect rect = rg.Rect;
      double left = Math.Max(5.0, (rect.Width - alertText.ActualWidth) / 2);
      double top = Math.Max(5.0, (rect.Height - 20 - alertText.ActualHeight) / 2);
      alertText.SetValue(Canvas.LeftProperty, left);
      alertText.SetValue(Canvas.TopProperty, top);
      alert.Visibility = Visibility.Visible;
    }

    protected void ButtonMouseEnter(object sender, MouseEventArgs e)
    {
      Path path = okRect;
      LinearGradientBrush lgb = path.Fill as LinearGradientBrush;
      lgb.GradientStops[0].Color = Color.FromArgb(255, 240, 188, 77);
    }

    protected void ButtonMouseLeave(object sender, EventArgs e)
    {
      Path path = okRect;
      LinearGradientBrush lgb = path.Fill as LinearGradientBrush;
      lgb.GradientStops[0].Color = Color.FromArgb(255, 180, 196, 139);
    }

    protected void OKClick(object sender, MouseEventArgs e)
    {
      alert.Visibility = Visibility.Collapsed;
    }

    private ChartModel _loadChartModel()
    {
      string[] seriesLabels = null, groupLabels = null;
      Color[] seriesColors = null;
      double[,] xValues = null, yValues = null;
      _getLabels("seriesLabels", ref seriesLabels);
      _getLabels("groupLabels", ref groupLabels);
      _getColors("seriesColors", ref seriesColors);
      _getValues("chartYValues", ref yValues);
      _getValues("chartXValues", ref xValues);

      double minYValue = double.Parse(_hdoc.GetElementById("minValueY").GetAttribute("value"));
      double maxYValue = double.Parse(_hdoc.GetElementById("maxValueY").GetAttribute("value"));
      double minXValue = double.Parse(_hdoc.GetElementById("minValueX").GetAttribute("value"));
      double maxXValue = double.Parse(_hdoc.GetElementById("maxValueX").GetAttribute("value"));

      string title = _hdoc.GetElementById("chartTitle").GetAttribute("value");
      string subTitle = _hdoc.GetElementById("chartSubTitle").GetAttribute("value");
      string footNote = _hdoc.GetElementById("chartFootNote").GetAttribute("value");

      ChartModel model = new ChartModel(seriesLabels, groupLabels, yValues, xValues, title, subTitle, footNote, seriesColors);

      model.MaxYValue = maxYValue;
      model.MaxXValue = maxXValue;
      model.MinYValue = minYValue;
      model.MinXValue = minXValue;

      return model;
    }

    private string _getSelectElementValue(string id)
    {
      HtmlElement select = _hdoc.GetElementById(id);
      HtmlElementCollection children = select.Children;
      List<HtmlElement> options = new List<HtmlElement>();

      foreach (HtmlElement elem in children)
      {
        if ("OPTION".Equals(elem.GetAttribute("nodeName")))
        {
          options.Add(elem);
        }
      }
      int selectedIndex = int.Parse(select.GetAttribute("selectedIndex"));
      return options[selectedIndex].GetAttribute("value");
    }

    private void _getLabels(string id, ref string[] labelValues)
    {
      HtmlElement table = _hdoc.GetElementById(id);
      HtmlElementCollection children = table.Children;
      int childCount = children.Count;

      HtmlElement tBody = children[childCount - 1];
      children = tBody.Children;
      int rowCount = children.Count;

      HtmlElement row, cell, input;
      labelValues = new string[rowCount];

      for (var i = 0; i < rowCount; ++i)
      {
        row = children[i];
        cell = row.Children[0];
        input = cell.Children[0];
        labelValues[i] = input.GetAttribute("value");
      }
    }

    private void _getColors(string id, ref Color[] colors)
    {
      HtmlElement table = _hdoc.GetElementById(id);
      HtmlElementCollection children = table.Children;
      int childCount = children.Count;

      HtmlElement tBody = children[childCount - 1];
      children = tBody.Children;
      int rowCount = children.Count;

      HtmlElement row, cell, input;
      colors = new Color[rowCount];

      string colorStr;
      for (var i = 0; i < rowCount; ++i)
      {
        row = children[i];
        cell = row.Children[0];
        input = cell.Children[0];
        colorStr = input.GetAttribute("value");

        if (colorStr.Length != 7)
        {
          throw new Exception("Invalid color format");
        }
        else
        {
          byte r = byte.Parse(colorStr.Substring(1, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
          byte g = byte.Parse(colorStr.Substring(3, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
          byte b = byte.Parse(colorStr.Substring(5, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
          colors[i] = Color.FromArgb(255, r, g, b);
        }
      }
    }

    private void _getValues(string id, ref  double[,] chartValues)
    {
      HtmlElement table = _hdoc.GetElementById(id);
      HtmlElementCollection children = table.Children;
      int childCount = children.Count;

      HtmlElement tBody = children[childCount - 1];
      HtmlElementCollection rows = tBody.Children;
      int rowCount = rows.Count;

      HtmlElement row, cell, input;

      chartValues = new double[rowCount, _seriesCount];

      for (var i = 0; i < rowCount; ++i)
      {
        row = rows[i];

        HtmlElementCollection cells = row.Children;
        int cellCount = cells.Count;

        for (var j = 0; j < cellCount; ++j)
        {
          cell = cells[j];
          input = cell.Children[0];
          chartValues[i, j] = Double.Parse(input.GetAttribute("value"));
        }
      }
    }

    private HtmlDocument _hdoc;
    string[] _groupLabels = { "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8", "G9", "G10" };
    string[] _seriesLabels = { "S1", "S2", "S3" };

    double[,] _chartYValues = {{135235, 155535, 141725},
                              {106765, 131725, 127868},
                              {108456, 119326, 139326},
                              {136765, 147265, 184349}, 
                              {107868, 113968, 174349},
                              {103019, 119145, 182080},
                              {149037, 156071, 187799},
                              {133013, 169140, 186010},
                              {139994, 186871, 158003}, 
                              {191246, 180196, 153177}};

    double[,] _chartXValues = {{6.1, 6.3, 6.5},
                                {6.8, 7.1,7.3},
                                {7.6, 7.8, 8.0},
                                {7.9, 8.4, 8.9},
                                {8.15, 8.45, 9.1},
                                {8.45, 8.55, 9.2}, 
                                {8.76, 8.75, 9.4},
                                {8.98, 8.95, 9.6},
                                {9.14, 9.25, 9.7},
                                {9.23, 9.48,9.88}};

    private int _seriesCount = 3;

    string[] _seriesColors = { "#E76D48", "#6EA6F3", "#9DCE6E", "#FCC46F", "#FF7FFF", "#AEAEAE" };

    // pie and funnel data
    string[] _pieSeriesLabels = { "S1", "S2", "S3", "S4", "S5", "S6" };
    string[] _pieGroupLabels = { "G1", "G2" };
    double[,] _pieChartYValues = {{135235, 155535, 141725, 106765, 131725,127868},
                               {108456, 119326, 139326, 136765, 147265,184349}};

    // Used By Gauges
    string[] _gaugeGroupLabels = { "Gauge1", "Gauge2" };
    string[] _gaugeSeriesLabels = { "" };

    double[,] _gaugeChartYValues = {{135},
                                    {106}};

    bool _isGuageType = false;
    bool _isPieType = false;
    private static LookAndFeel _transparentLF;

    private string[,] _imageIDs =  {
      {"bar", "VBAR"},
      {"pie", "PIE"},
      {"area", "AREA"},
      {"line", "LINE"},
      {"scatter", "SCATTER_PLOT"},
      {"funnel", "FUNNEL"},
      {"radar", "RADAR"},
      {"radararea", "RADAR_AREA"},
      {"gauge", "CIRCULAR_GAUGE"},
      {"semigauge", "SEMI_CIRCULAR_GAUGE"},
      {"stackedarea", "AREA_STACKED"},
      {"cbar", "CYLINDERBAR"},
      {"hbar", "HBAR"},
      {"stackedbar", "VBAR_STACKED"},
      {"stackedhbar", "HBAR_STACKED"},
      {"barline", "BAR_LINE_COMBO"},
      {"bararea", "BAR_AREA_COMBO"}
    };
  }
}
